fix(loss): count num_valid_samples from the sample mask, not the batch dim - #3850
Open
tianyi-zhang-02 wants to merge 5 commits into
Open
fix(loss): count num_valid_samples from the sample mask, not the batch dim#3850tianyi-zhang-02 wants to merge 5 commits into
tianyi-zhang-02 wants to merge 5 commits into
Conversation
…h dim
Six losses in this file derive num_valid_samples from the sample mask.
Three derive it from the batch dimension instead: MseValueLossFn from
values.shape[0], and both distillation losses from input_ids.shape[0].
That number is a gate, not just a log line. dtensor_policy_worker,
dtensor_policy_worker_v2 and dtensor_value_worker_v2 all do
if num_valid_samples > 0:
mb_losses.append(loss.item())
all_mb_metrics.append(loss_metrics)
so a microbatch whose sample_mask is entirely zero -- which is what
overlong filtering, env-flagged masking and the critic's
seq_logprob_error_threshold filter produce -- reports the raw batch size,
passes the gate, and contributes its zero loss to the step's reported mean.
dpo.py and rm.py additionally use the value as a weighted-average
denominator.
DistillationLossFn keeps a batch-dimension fallback: its masking branch is
conditional, and with no mask every sample is valid by definition.
Tests are CPU-only -- they build the loss inputs directly rather than going
through prepare_loss_input, so no GPU and no distributed init. The
cross-tokenizer loss gets the same one-line change but no new test: every
CPU test for it calls the private helpers, and none reaches __call__ where
the metrics dict is built.
Signed-off-by: Tianyi Zhang <zhangtianyi975@gmail.com>
Signed-off-by: Tianyi Zhang <123608656+tianyi-zhang-02@users.noreply.github.com>
tianyi-zhang-02
force-pushed
the
fix-num-valid-samples
branch
from
August 26, 2026 18:16
cfdf9c2 to
6634ab2
Compare
…IA-NeMo#3496 NVIDIA-NeMo#3496 replaces DistillationLossFn's unmasked-mean fallback with a raise. Until it lands the fallback is live and must report the batch size; after it lands the branch is gone and the raise is the only correct behaviour. Asserting one of them unconditionally makes the two PRs fail as a pair while each passes alone. That is not hypothetical -- it is what happened when I merged the whole stack onto main to check exactly this. Signed-off-by: Tianyi Zhang <123608656+tianyi-zhang-02@users.noreply.github.com>
tianyi-zhang-02
force-pushed
the
fix-num-valid-samples
branch
from
August 28, 2026 15:39
7c69abb to
a3ec715
Compare
Signed-off-by: Tianyi Zhang <123608656+tianyi-zhang-02@users.noreply.github.com>
Exercise the public cross-tokenizer loss call for partially and fully masked microbatches so the worker-facing gate is pinned to sample_mask.sum(). Keep the no-mask distillation expectation deterministic against the current main branch rather than accepting behavior from an unmerged PR. Signed-off-by: Tianyi Zhang <123608656+tianyi-zhang-02@users.noreply.github.com>
Signed-off-by: Tianyi Zhang <123608656+tianyi-zhang-02@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Counts
num_valid_samplesfrom the effectivesample_maskin the value, distillation, and cross-tokenizer distillation losses.Workers use this metric as an inclusion gate. Counting the batch dimension lets a fully masked microbatch through even though it contributes zero loss, which dilutes step metrics. The unmasked distillation fallback still reports the batch size.
torch.count_nonzero(sample_mask)is intentional:sample_maskmay contain fractional loss multipliers, but this diagnostic counts participating samples rather than summing their weights.Validation
Final SHA:
4358db26fd719a9c39410d217c368a810ee56f76, based on upstreammainatccbcd4cc5.Runpod Secure Cloud,
nvcr.io/nvidia/nemo-rl:v0.7.0, Python 3.13.14, PyTorch 2.11.0+cu130:tests/unit/algorithms/test_num_valid_samples.py: 10 passedNo GPU was needed; these tests call the loss functions directly.